package com.broada.apm.template.impl;

import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.template.RuleMatchEstimate;

/**
 * 默认规则匹配判断，规则如下：<br>
 * 1.规则最小因子为一个查找字符串(暂时用这个，因为正则表达式效率偏低)<br>
 * 2.规则仅支持"或(or)"、"且(and)"、"非(!)"，对于"非"运算放在最小规则因子前面<br>
 *   <b>注:</b>对于任何复杂的规则运算最终都可以转换成或、且、非三种运算来表示<br>
 * 3.规则直接的关系运算符必须以"英文逗号(,)"隔开<br>
 * 比如chrome浏览器判断规则：chrome,and,!opera,and,!opr
 * @author jianfei.xu
 * @date   2016年3月17日
 *
 */
public class DefaultRuleMatchEstimate implements RuleMatchEstimate {
	
	/**
	 * 构造函数
	 * @param ruleStr	:规则字符串
	 */
	public DefaultRuleMatchEstimate(String ruleStr) {
		this.ruleStr = ruleStr;
		parse(this.ruleStr);
	}
	
	/**
	 * 主串是否匹配规则
	 * @param mainStr	:主串
	 * @return			:true匹配,false不匹配
	 */
	@Override
	public boolean matches(String mainStr) {
		if(null == mainStr || "".equals(mainStr) || null == aggregationRules) return true;
		
		int nextRelaPos = 0;
		String tmpStr;
		String nodePrefix = "node_";
		String valPrefix = "val_";
		boolean tmpVal;
		Stack<String> tmpStack = new Stack<String>();
		for(int nextRulePos = 0; nextRulePos < aggregationRules.ruleNodeList.size();) {
			tmpStack.push(nodePrefix + nextRulePos);
			nextRulePos++;
			
			while(nextRelaPos < aggregationRules.relaOperList.size()) {
				if(and.equals(aggregationRules.relaOperList.get(nextRelaPos))) {//且运算
					nextRelaPos++;
					tmpStr = tmpStack.pop();
					if(tmpStr.startsWith(nodePrefix)) {//规则节点之间且运算
						tmpVal = aggregationRules.ruleNodeList.get(Integer.parseInt(tmpStr.substring(nodePrefix.length()))).validate(mainStr);
						if(tmpVal) tmpVal = aggregationRules.ruleNodeList.get((nextRulePos)).validate(mainStr);
						tmpStack.push(valPrefix + tmpVal);
						nextRulePos++;
						continue;
					}
					
					if(Boolean.parseBoolean(tmpStr.substring(valPrefix.length()))) {//临时值为true,且运算取决于下一个节点
						tmpVal = aggregationRules.ruleNodeList.get((nextRulePos)).validate(mainStr);
						tmpStack.push(valPrefix + tmpVal);
						nextRulePos++;
						continue;
					}
					
					tmpStack.push(valPrefix + "false"); //临时值为false,且运算肯定为false
					nextRulePos++;
					continue;
				}
				
				nextRelaPos++;
				break;
			}
			
		}
		
		while(!tmpStack.isEmpty()) {//栈不为空(或运算)
			tmpStr = tmpStack.pop();
			if(tmpStr.startsWith(valPrefix)) {//临时值
				if(Boolean.parseBoolean(tmpStr.substring(valPrefix.length()))) return true;
				continue;
			}
			
			tmpVal = aggregationRules.ruleNodeList.get(Integer.parseInt(tmpStr.substring(nodePrefix.length()))).validate(mainStr);
			if(tmpVal) return true;
		}
		
		return false;
	}
	
	/**
	 * 解析规则字符串
	 * @param ruleStr	:规则字符串
	 */
	private void parse(String ruleStr) {
		if(null == ruleStr || "".equals(ruleStr)) return;
		
		String tmpStr = null;
		RuleNode tmpRuleNode = null;
		aggregationRules = new AggregationRules();
		String[] ruleArray = ruleStr.split(",");
		for(int i = 0; i < ruleArray.length; i++) {
			tmpStr = ruleArray[i].trim();
			if("".equals(tmpStr)) {
				LOG.error("规则配置不合法，将忽略规则配置...");
				aggregationRules = null;
				return;
			}
			
			if(0 == i % 2) {//偶数位置表示规则节点
				tmpRuleNode = new RuleNode();
				if(tmpStr.startsWith(not)) {
					tmpRuleNode.isNegation = true;
					tmpStr = tmpStr.substring(not.length());
				}
				tmpRuleNode.regPattern = Pattern.compile(tmpStr);
				aggregationRules.ruleNodeList.add(tmpRuleNode);
				continue;
			}
			
			switch (tmpStr.toLowerCase()) {//关系运算符
				case and:
					aggregationRules.relaOperList.add(and);
					break;
				case or:
					aggregationRules.relaOperList.add(or);
					break;
				default:
					LOG.error("关系运算符配置不合法，将忽略规则配置...");
					aggregationRules = null;
					return;
			}
			
		}
		
	}
	
	/**
	 * 聚合规则
	 * @author jianfei.xu
	 * @date   2016年3月17日
	 */
	private class AggregationRules {
		List<String> relaOperList = new LinkedList<String>(); //关系运算符
		
		List<RuleNode> ruleNodeList = new LinkedList<RuleNode>(); //规则节点
	}
	
	/**
	 * 规则节点
	 * @author jianfei.xu
	 * @date   2016年3月17日
	 */
	private class RuleNode {
		boolean isNegation = false; //是否取反(true:取反,false:不取反)
		
		Pattern regPattern; //匹配模式
		
		/**
		 * 验证
		 * @param mainStr	:验证主串
		 * @return			:true验证通过,false验证不通过
		 */
		public boolean validate(String mainStr) {
			boolean retVal = regPattern.matcher(mainStr).find(); //因为效率原因,目前用find,以后替换成match
			
			return isNegation? !retVal : retVal;
		}
		
	}
	
	private AggregationRules aggregationRules; //聚合规则
	
	private String ruleStr; //规则字符串
	
	private static final String and = "and"; //且运算符标识
	
	private static final String or = "or"; //或运算符标识
	
	private static final String not = "!"; //非运算符标识
	
	private static Logger LOG = LoggerFactory.getLogger(DefaultRuleMatchEstimate.class);
	
}
